package com.rain.codemother.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.rain.codemother.annotation.AuthCheck;
import com.rain.codemother.common.BaseResponse;
import com.rain.codemother.common.DeleteRequest;
import com.rain.codemother.common.ResultUtils;
import com.rain.codemother.constant.AppConstant;
import com.rain.codemother.constant.UserConstant;
import com.rain.codemother.exception.BusinessException;
import com.rain.codemother.exception.ErrorCode;
import com.rain.codemother.exception.ThrowUtils;
import com.rain.codemother.model.dto.app.*;
import com.rain.codemother.model.entity.App;
import com.rain.codemother.model.entity.User;
import com.rain.codemother.model.enums.CodeGenTypeEnum;
import com.rain.codemother.model.vo.AppVo;
import com.rain.codemother.rateLimit.annotation.RateLimit;
import com.rain.codemother.rateLimit.enums.RateLimitType;
import com.rain.codemother.service.ChatHistoryService;
import com.rain.codemother.service.ProjectDownloadService;
import com.rain.codemother.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.rain.codemother.service.AppService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 *  控制层。
 *
 * @author <a href="https://github.com/liyupi">程序员刘诗雨</a>
 */
@RestController
@RequestMapping("/app/")
public class AppController {

    @Autowired
    private AppService appService;
    @Resource
    private UserService userService;
    @Resource
    private ProjectDownloadService projectDownloadService;


    @GetMapping("download/{appId}")
    public void downloadAppCode(@PathVariable Long appId,
                                                HttpServletRequest request,
                                                HttpServletResponse response) {
//        1,参数，权限校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR);
        App app = appService.getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);

        User loginUser = userService.getLoginUser(request);
        if(!app.getUserId().equals(loginUser.getId())){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
//        2，构建应用代码路径
        String codeGenType = app.getCodeGenType();
        String sourceDirPath  = AppConstant.CODE_OUTPUT_ROOT_DIR+
                File.separator + codeGenType + "_" + appId;
        File sourceDir = new File(sourceDirPath);
        if(!sourceDir.exists() || !sourceDir.isDirectory()){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"应用代码不存在");
        }
//        3,下载文件名
        String downloadFileName = String.valueOf(appId);
        projectDownloadService.downloadProjectAsZip(sourceDirPath, downloadFileName, response);
    }


    @PostMapping("deploy")
    public BaseResponse<String> deployApp(@RequestBody AppDeployRequest appDeployRequest,
                                     HttpServletRequest request) {
        ThrowUtils.throwIf(appDeployRequest==null, ErrorCode.PARAMS_ERROR);

        User loginUser = userService.getLoginUser(request);
        Long appId = appDeployRequest.getAppId();
        String deployUrl = appService.deployApp(appId, loginUser);
        return ResultUtils.success(deployUrl);
    }
    /**
     * 应用聊天生成代码（流式 SSE）
     *
     * @param appId   应用 ID
     * @param message 用户消息
     * @param request 请求对象
     * @return 生成结果流
     */
    @GetMapping(value = "/chat/gen/code", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @RateLimit(limitType = RateLimitType.USER, rate = 5, rateInterval = 60, message = "AI 对话请求过于频繁，请稍后再试")
    public Flux<ServerSentEvent<String>> chatToGenCode(@RequestParam Long appId,
                                                       @RequestParam String message,
                                                       HttpServletRequest request) {
        // 参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用 id 错误");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "提示词不能为空");
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 调用服务生成代码（SSE 流式返回）
        Flux<String> contentFlux = appService.chatToGenCode(message, appId, loginUser);
        return contentFlux
                .map(chunk -> {
                    Map<String, String> wrapper = Map.of("d", chunk);
                    String jsonData = JSONUtil.toJsonStr(wrapper);
                    return ServerSentEvent.<String>builder()
                            .data(jsonData)
                            .build();
                })
                .concatWith(Mono.just(
                        // 发送结束事件
                        ServerSentEvent.<String>builder()
                                .event("done")
                                .data("")
                                .build()
                ));
    }

    @PostMapping("add")
    public BaseResponse<Long> addApp(@RequestBody AppAddRequest appAddRequest,
                                     HttpServletRequest request) {
        ThrowUtils.throwIf(appAddRequest==null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        Long appId = appService.addApp(appAddRequest, loginUser);
        return ResultUtils.success(appId);
    }

    @PostMapping("update")
    public BaseResponse<Boolean> updateApp(@RequestBody AppUpdateRequest appUpdateRequest,
                                     HttpServletRequest request) {
        ThrowUtils.throwIf(appUpdateRequest==null || appUpdateRequest.getId()==null, ErrorCode.PARAMS_ERROR);
        Long appId = appUpdateRequest.getId();
        App oldApp = appService.getById(appId);
//        app是否存在
        ThrowUtils.throwIf(oldApp==null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
//        权限校验
        if(!oldApp.getUserId().equals(loginUser.getId())){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"仅仅本人可跟新");
        }
//        构造入库
        App app = new App();
        app.setId(appId);
        app.setEditTime(LocalDateTime.now());
        app.setAppName(appUpdateRequest.getAppName());

        boolean update = appService.updateById(app);
        ThrowUtils.throwIf(!update,ErrorCode.PARAMS_ERROR);
        return ResultUtils.success(true);
    }

    @PostMapping("delete")
    public BaseResponse<Boolean> deleteApp(@RequestBody DeleteRequest deleteRequest,
                                           HttpServletRequest request) {
        ThrowUtils.throwIf(deleteRequest.getId()<0 || deleteRequest.getId()==null, ErrorCode.PARAMS_ERROR);
        Long appId = deleteRequest.getId();
        App oldApp = appService.getById(appId);
//        app是否存在
        ThrowUtils.throwIf(oldApp==null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
//        权限校验
        if(!oldApp.getUserId().equals(loginUser.getId())
                && !UserConstant.ADMIN_ROLE.equals(loginUser.getUserRole())){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"仅仅本人或管理员可删除");
        }
//        删除操作
        boolean delete = appService.removeById(oldApp);
        ThrowUtils.throwIf(!delete,ErrorCode.PARAMS_ERROR);
        return ResultUtils.success(true);
    }

    @GetMapping("get/vo")
    public BaseResponse<AppVo> getAppVo(long appId) {
        ThrowUtils.throwIf(appId<0, ErrorCode.PARAMS_ERROR);
        App app = appService.getById(appId);
//        app是否存在
        ThrowUtils.throwIf(app==null, ErrorCode.PARAMS_ERROR);
        AppVo appVo = appService.getAppVo(app);
        return ResultUtils.success(appVo);
    }

    /**
     * 分页获取当前用户创建的app列表
     * @param appQueryRequest
     * @param request
     * @return
     */
    @PostMapping("my/page/vo")
    public BaseResponse<Page<AppVo>> getMyAppVoByPage(@RequestBody AppQueryRequest appQueryRequest,
                                                      HttpServletRequest request) {
        ThrowUtils.throwIf(appQueryRequest==null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        int pageNum = appQueryRequest.getPageNum();
        int pageSize = appQueryRequest.getPageSize();
//        限制爬虫
        ThrowUtils.throwIf(pageSize>20,ErrorCode.PARAMS_ERROR);
//        仅仅能查看自己的app？
        appQueryRequest.setUserId(loginUser.getId());
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        Page<App> appPage = appService.page(new Page<>(pageNum, pageSize), queryWrapper);
        Page<AppVo> appVoPage = new Page<>(pageNum, pageSize);
        List<AppVo> appVoList = appService.getAppVoList(appPage.getRecords());
        appVoPage.setRecords(appVoList);
        return ResultUtils.success(appVoPage);
    }

    /**
     * 分页获取精选的app列表
     * @param appQueryRequest
     * @param request
     * @return
     */
    @Cacheable(
            value = "good_app_page",
            key = "T(com.rain.codemother.utils.CacheKeyUtils).generateKey(#appQueryRequest)",
            condition = "#appQueryRequest.pageNum <= 10"
    )
    @PostMapping("good/page/vo")
    public BaseResponse<Page<AppVo>> getGoodAppVoByPage(@RequestBody AppQueryRequest appQueryRequest,
                                                      HttpServletRequest request) {
        ThrowUtils.throwIf(appQueryRequest==null, ErrorCode.PARAMS_ERROR);
        int pageNum = appQueryRequest.getPageNum();
        int pageSize = appQueryRequest.getPageSize();
//        限制爬虫
        ThrowUtils.throwIf(pageSize>20,ErrorCode.PARAMS_ERROR);
//       查询精选的app列表
        appQueryRequest.setPriority(AppConstant.GOOD_APP_PRIORITY);
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        Page<App> appPage = appService.page(new Page<>(pageNum, pageSize), queryWrapper);
        Page<AppVo> appVoPage = new Page<>(pageNum, pageSize);
        List<AppVo> appVoList = appService.getAppVoList(appPage.getRecords());
        appVoPage.setRecords(appVoList);
        return ResultUtils.success(appVoPage);
    }

    @PostMapping("admin/delete")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> deleteAppByAdmin(@RequestBody DeleteRequest deleteRequest,
                                           HttpServletRequest request) {
        ThrowUtils.throwIf(deleteRequest.getId()<0 || deleteRequest.getId()==null, ErrorCode.PARAMS_ERROR);
        Long appId = deleteRequest.getId();
        App oldApp = appService.getById(appId);
//        app是否存在
        ThrowUtils.throwIf(oldApp==null, ErrorCode.PARAMS_ERROR);

//        删除操作
        boolean delete = appService.removeById(oldApp);
        ThrowUtils.throwIf(!delete,ErrorCode.PARAMS_ERROR);
        return ResultUtils.success(true);
    }

    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @PostMapping("admin/update")
    public BaseResponse<Boolean> updateAppByAdmin(@RequestBody AppAdminUpdateRequest appAdminUpdateRequest,
                                           HttpServletRequest request) {
        ThrowUtils.throwIf(appAdminUpdateRequest==null || appAdminUpdateRequest.getId()==null, ErrorCode.PARAMS_ERROR);
        Long appId = appAdminUpdateRequest.getId();
        App oldApp = appService.getById(appId);
//        app是否存在
        ThrowUtils.throwIf(oldApp==null, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);

//        构造入库
        App app = new App();
        BeanUtils.copyProperties(appAdminUpdateRequest,app);
        app.setEditTime(LocalDateTime.now());

        boolean update = appService.updateById(app);
        ThrowUtils.throwIf(!update,ErrorCode.PARAMS_ERROR);
        return ResultUtils.success(true);
    }

    /**
     * 管理员分页获取app列表
     * @param appQueryRequest
     * @param request
     * @return
     */
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @PostMapping("admin/page/vo")
    public BaseResponse<Page<AppVo>> getAppVoByPageByAdmin(@RequestBody AppQueryRequest appQueryRequest,
                                                      HttpServletRequest request) {
        ThrowUtils.throwIf(appQueryRequest==null, ErrorCode.PARAMS_ERROR);
        int pageNum = appQueryRequest.getPageNum();
        int pageSize = appQueryRequest.getPageSize();

        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        Page<App> appPage = appService.page(new Page<>(pageNum, pageSize), queryWrapper);
        Page<AppVo> appVoPage = new Page<>(pageNum, pageSize);
        List<AppVo> appVoList = appService.getAppVoList(appPage.getRecords());
        appVoPage.setRecords(appVoList);
        return ResultUtils.success(appVoPage);
    }

    /**
     * 管理员根据 id 获取应用详情
     *
     * @param id 应用 id
     * @return 应用详情
     */
    @GetMapping("/admin/get/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<AppVo> getAppVOByIdByAdmin(long id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        // 查询数据库
        App app = appService.getById(id);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        // 获取封装类
        return ResultUtils.success(appService.getAppVo(app));
    }

}
